// ThreeFishCore.h

#pragma once

using namespace System;
using namespace System::Runtime::InteropServices;

//#define UInt64	unsigned __int64

namespace SkeinLib
{
	//public ref class ThreeFishCore
	public ref class ThreeFishCore
	{
		public:
			static void Process256(const UInt64[], const UInt64[], const UInt64[], bool, UInt64[]);
			static void InvProcess256(const UInt64[], const UInt64[], const UInt64[], UInt64[]);
			static void Process512(const UInt64[], const UInt64[], const UInt64[], bool, UInt64[]);
			static void InvProcess512(const UInt64[], const UInt64[], const UInt64[], UInt64[]);
			static void Process1024(const UInt64[], const UInt64[], const UInt64[], bool, UInt64[]);
			static void InvProcess1024(const UInt64[], const UInt64[], const UInt64[], UInt64[]);
		private:
			static UInt64 UniqueK(const UInt64[], int);
			static const UInt64 ThreeFishParity = 0x1BD11BDAA9FC1A22;
			//static void MIX(UInt64*, UInt64*, int);
			//static void INVMIX(UInt64*, UInt64*, int);
	};

	[DllImport("stdlib.dll", CharSet=CharSet::Auto)]   
	extern "C" unsigned __int64 _rotl64(unsigned __int64, int);

	[DllImport("stdlib.dll", CharSet=CharSet::Auto)]   
	extern "C" unsigned __int64 _rotr64(unsigned __int64, int);

	UInt64 SkeinLib::ThreeFishCore::UniqueK(const UInt64 input[], int length)
	{
		UInt64 result = ThreeFishParity;
		if (input == 0 || length == 0) //on null input or 0 length, just return the constant
			return result;
		for(int i = 0; i < length; i++)
		{
			result ^= input[i];
		}
		return result;
	}

	//do not __forceinline the following MIX functions, that takes WAY too long to compile, produces bloated binaries, 
	// and provides no speed benefits whatsoever
	//*Y = (UInt64)(*Y << N) + (UInt64)(*Y >> (64 - N)); //ROTATE LEFT
	//*Y = (UInt64)(*Y >> N) + (UInt64)(*Y << (64 - N)); //ROTATE RIGHT

	//void SkeinLib::ThreeFishCore::MIX(UInt64 *X, UInt64 *Y, int N)
	//{
	//	*X += *Y; *Y= _rotl64(*Y, N); *Y ^= *X;
	//}

	//void SkeinLib::ThreeFishCore::INVMIX(UInt64 *X, UInt64 *Y, int N)
	//{
	//	*Y ^= *X; *Y = _rotr64(*Y, N); *X -= *Y;
	//}

}
